package torres.controller;

import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.HashSet;
import java.util.LinkedHashSet;

import torres.ability.Ability;
import torres.ability.AbilityManager;
import torres.ability.ActionAbility;
import torres.ability.NonActionAbility;
import torres.entity.Avatar;
import torres.entity.Skill;
import torres.fileIO.Saver;
import torres.map.Map;
import torres.map.World;
import torres.view.AreaViewPort;
import torres.view.MainView;

/**
 * @author Torres
 * The Controller in the MVC architecture; parses keyboard 
 * and mouse input and issues the appropriate commands.
 */
public class Controller implements KeyListener, MouseListener {
	private static Controller instance;
	private static Avatar avatar = World.getInstance().getPlayer();
	private static HashSet<Integer> keys; 
	private static Configuration config;
	private static World world = World.getInstance();
	private static Map currentMap;
	
	private static boolean controlCurrentlyPressed;
	
	/**
	 *
	 * Controller constructor creates the controller instance that relays user input and dispatches commands
	 * as needed.
	 */
	private Controller() {
		keys = new HashSet<Integer>();
		
		config = new Configuration();
		File file = new File("src/resources/configs/default.conf");
		config.loadConfiguration(file);
	}
	
	/**
	 * Returns an instance of Controller.
	 * Creates one if one does not exist.
	 * @return Controller
	 */
	public static Controller getInstance(){
		if(instance == null)
			instance = new Controller();
		return instance;
			
	}
	
	/**
	 * Adds a KeyListener to the given component passed.  By convention Component should superclass AreaViewPort.
	 * @param main the Component that wants to add KeyListener
	 */
	public static void addKeyListener(AreaViewPort view) {
		view.addKeyListener(new Controller());
	}
	
	/**
	 *
	 * Adds a MouseListener to the given component passed.  By convention Component should superclass AreaViewPort.
	 * @param main the main Component that wants to add MouseListener
	 */
	public static void addMouseListener(AreaViewPort view) {
		view.addMouseListener(new Controller());
	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyPressed(KeyEvent arg0) {
		
		int key = arg0.getKeyCode();
		keys.add(key);
		
		//must check for pausing here because the controller
		//will never process input if the game loop is frozen
		if(keys.contains(config.getKeyCode("P"))) {
			Command.pause();
		}
		if(keys.contains(config.getKeyCode("I"))) {
			Command.showInventory();
		}
		if(keys.contains(config.getKeyCode("J"))) {
			Command.showAbilityMenuView();
		}
		if(keys.contains(config.getKeyCode("H"))) {
			Command.showActionMenu();
		}
	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyReleased(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyReleased(KeyEvent arg0) {		
		int key = arg0.getKeyCode();
		keys.remove(key);
		if(key == KeyEvent.VK_CONTROL)
			controlCurrentlyPressed = false;
	}

	/* (non-Javadoc)
	 * @see java.awt.event.KeyListener#keyTyped(java.awt.event.KeyEvent)
	 */
	@Override
	public void keyTyped(KeyEvent arg0) {
		
	}

	/**
	 * Mouse events
	 */
	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseClicked(MouseEvent e) {
		int x = e.getX();
		int y = e.getY();
		
		if(x >= 50 && x <= 130 && y >= 95 && y <= 175 ) {
			Command.showInventory();
		}
		else if(torres.RunGame.gameLoop.getInventory() == true){
			Command.interactWithItem(e);
		}
		else if(World.getInstance().getPlayer().getActionMenu()) {
			Command.interactWithActionMenu(e);
		}
		if(torres.RunGame.gameLoop.getSkillMenu()) {
			Command.interactWithSkillMenu(e);
		}
		if(torres.RunGame.gameLoop.getShopMenu()) {
			Command.interactWithShop(e);
		}
		if (torres.RunGame.gameLoop.getAbilityMenu()) {
			int yOffset = 30;
			int xOffset = 20;
			int screenWidth = MainView.getInstance().getAbilityMenuView().getScreenWidth(); 
			int screenHeight = MainView.getInstance().getAbilityMenuView().getScreenHeight();
		
		
			Rectangle rect = new Rectangle(screenWidth/2 - (screenWidth/3) + 20 + xOffset*12,
					screenHeight/2 +20+ yOffset-31/2-5,31, 31*7);
			if(rect.contains(e.getPoint()))
				Command.interactWithSkillPoint(e, 
					MainView.getInstance().getAbilityMenuView().getSkillHash(
							avatar.retreiveSkillEnumList(new LinkedHashSet<Skill>())), 
					MainView.getInstance().getAbilityMenuView().getImageRadius());
			
			
			rect = new Rectangle(screenWidth/2+ xOffset+20,
					screenHeight/2-screenHeight*2/3*7/16+10, 300, 30*10);
			System.out.println("Command.interactWithSkillPoint(): rect.contains(point): "+ rect.contains(e.getPoint()) + " Rect: " + rect.getLocation());
			if (rect.contains(e.getPoint())) {
				Command.interactWithAbility(e, MainView.getInstance().getAbilityMenuView().returnRectangleAreas());
				MainView.getInstance().draw();
			}	
		}
		if(torres.RunGame.gameLoop.getPurchaseMenu()) {
			Command.interactWithPurchaseMenu(e);
		}
		if(torres.RunGame.gameLoop.getActionInventoryMenu()) {
			Command.interactWithActionItem(e);
		}
		//System.out.println("Controller.mouseClicked(): X: " + x + " Y: "+ y);
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
	 */
	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
	 */
	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * Reads keyboard input and does appropriate actions associated with inputs. 
	 */
	public static void process() {
		if(keys.contains(config.getKeyCode("UP"))) {
			if(keys.contains(config.getKeyCode("LEFT"))) {
				Command.moveEntity(Direction.NORTHWEST, World.getInstance().getPlayer());
			}
			else if(keys.contains(config.getKeyCode("RIGHT"))) {
				Command.moveEntity(Direction.NORTHEAST, World.getInstance().getPlayer());
			}
			else {
				Command.moveEntity(Direction.NORTH, World.getInstance().getPlayer());
			}
		
		}
		else if(keys.contains(config.getKeyCode("DOWN"))){
			if(keys.contains(config.getKeyCode("LEFT"))) {
				Command.moveEntity(Direction.SOUTHWEST, World.getInstance().getPlayer());
			}
			else if(keys.contains(config.getKeyCode("RIGHT"))) {
				Command.moveEntity(Direction.SOUTHEAST, World.getInstance().getPlayer());
			}
			else {
				Command.moveEntity(Direction.SOUTH, World.getInstance().getPlayer());
			}
		}
		else if(keys.contains(config.getKeyCode("RIGHT"))){
			Command.moveEntity(Direction.EAST, World.getInstance().getPlayer());
		}
		else if(keys.contains(config.getKeyCode("LEFT"))){
			Command.moveEntity(Direction.WEST, World.getInstance().getPlayer());
		}
		
		if(keys.contains(config.getKeyCode("ESCAPE"))) {
			
			System.exit(0);
		}
		
		currentMap = World.getInstance().getCurrentMap();
		if(currentMap.equals(world.getCombatArena())) {
			Ability[] a = returnAttackList();
			if(keys.contains(config.getKeyCode("1"))) {
				//Element elem, int range, Direction direction, Location location, int power, int accuracy
				//ActionAbility a = AbilityManager.getInstance().getActionAbility(100);
				if (a[0] != null)
					World.getInstance().getPlayer().attemptActionAbility((ActionAbility)a[0]);
				//Thread t = new Thread(new LinearAction(Effect.PHYSICAL, 8, World.getInstance().getPlayer().getDirection(), Location.locationInDirection(World.getInstance().getPlayer().getLocation(), World.getInstance().getPlayer().getDirection()), 100, 100, 100));
				//t.start();
			}
			if (keys.contains(config.getKeyCode("2"))) {
				//Thread t = new Thread(new AngularAction(Element.HEAL, 3, World.getInstance().getPlayer().getDirection(), Location.locationInDirection(World.getInstance().getPlayer().getLocation(), World.getInstance().getPlayer().getDirection()), 100, 100, 300));
				//t.start();
				//System.out.println("Direction: " + World.getInstance().getPlayer().getDirection());
				//System.out.println("Location: " + World.getInstance().getPlayer().getLocation());
				//ActionAbility a = AbilityManager.getInstance().getActionAbility(400);
				//World.getInstance().getPlayer().attemptActionAbility(a);
				if (a[1] != null)
					World.getInstance().getPlayer().attemptActionAbility((ActionAbility)a[1]);
			}
			if (keys.contains(config.getKeyCode("3"))) {
				//Thread t = new Thread(new AngularAction(Element.HEAL, 3, World.getInstance().getPlayer().getDirection(), Location.locationInDirection(World.getInstance().getPlayer().getLocation(), World.getInstance().getPlayer().getDirection()), 100, 100, 300));
				//t.start();
				//System.out.println("Direction: " + World.getInstance().getPlayer().getDirection());
				//System.out.println("Location: " + World.getInstance().getPlayer().getLocation());
				//ActionAbility a = AbilityManager.getInstance().getActionAbility(400);
				//World.getInstance().getPlayer().attemptActionAbility(a);
				if (a[2] != null)
					World.getInstance().getPlayer().attemptActionAbility((ActionAbility)a[2]);
			}
		}
		
		if(keys.contains(config.getKeyCode("0"))) {
			ActionAbility a = AbilityManager.getInstance().getActionAbility(300);
			World.getInstance().getPlayer().attemptActionAbility(a);
			//Thread t = new Thread(new RadialAction(Effect.FIRE, 10, new Location(5, 5), 100, 100, 500));
			//t.setName("0-Key" + t.getId());
			//t.start();
		}
		if(keys.contains(KeyEvent.VK_4)) {
			ActionAbility a = AbilityManager.getInstance(). getActionAbility(200);
			World.getInstance().getPlayer().attemptActionAbility(a);
			//a.useAbility(World.getInstance().getPlayer());
		}
		if(keys.contains(KeyEvent.VK_5)) {
			ActionAbility a = AbilityManager.getInstance(). getActionAbility(201);
			World.getInstance().getPlayer().attemptActionAbility(a);
			//a.useAbility(World.getInstance().getPlayer());
		}
		if(keys.contains(KeyEvent.VK_6)) {
			ActionAbility a = AbilityManager.getInstance(). getActionAbility(204);
			World.getInstance().getPlayer().attemptActionAbility(a);
			//a.useAbility(World.getInstance().getPlayer());
		}
		if(keys.contains(KeyEvent.VK_7)) {
			NonActionAbility naa = AbilityManager.getInstance().getNonActionAbility(502);
			World.getInstance().getPlayer().attemptNonActionAbility(naa);
			//naa.useAbility(World.getInstance().getPlayer());
		}
		if(keys.contains(KeyEvent.VK_8)) {
			ActionAbility a = AbilityManager.getInstance(). getActionAbility(301);
			World.getInstance().getPlayer().attemptActionAbility(a);
			//World.getInstance().getPlayer().attemptActionAbility(a);
			//a.useAbility(World.getInstance().getPlayer());
		}
		if(keys.contains(KeyEvent.VK_CONTROL)) {
			NonActionAbility c = AbilityManager.getInstance().getNonActionAbility(500);
			//CreepAbility c = new CreepAbility("creep");
			if(!controlCurrentlyPressed) {
				controlCurrentlyPressed = true;
				//c.useAbility(World.getInstance().getPlayer());
				if(World.getInstance().getPlayer().isVisible())
					World.getInstance().getPlayer().attemptNonActionAbility(c);
				else
					World.getInstance().getPlayer().setVisible();
			}
		}
		if(keys.contains(config.getKeyCode("Q"))) {
			Avatar avatar = World.getInstance().getPlayer(); 
			avatar.setExperience(avatar.getExperience()+1000);
			//avatar.updateLevel();
		}
		if(keys.contains(KeyEvent.VK_F1))
			Saver.save("test.txt");
		if (keys.contains(KeyEvent.VK_F2)) {
			Saver.load(new File("test.txt"));
		}
		if(keys.contains(config.getKeyCode("H"))) {
			
			Command.showActionMenu();
		}
		if (keys.contains(config.getKeyCode("1"))) {
			
		}
	}
	public static Ability[] returnAttackList() {
		LinkedHashSet<Ability> ability = avatar.getOccupation().getAttackList();
		Ability[] abilities = new Ability[3];
		int i = 0;
		for (Ability abl : ability) {
			abilities[i++] = abl;
		}
		return abilities;
			
			
		
	}
}
